#pragma once

#include <string>
#include <iostream>
#include <math.h>

#include "targetver.h"
#include <windows.h>

#include <stdio.h>
#include <tchar.h>
#include <time.h>

#include <map>
#include <set>

#include <mpi.h>

using namespace std;

// Short dwarf's description.
#define DWARF_NAME (char*)"Unstructured Grid, unmanaged mpi kernel."

// Constants for output files's names
#define DWARF_NAME_OUTPUT (char*)"Dwarf.Unmanaged.Mpi"
#define PROFILE_TXT (char*)".Profile.txt"
#define RESULT_TXT (char*)".Result.txt"

// Default size for buffer.
#define BUFFER_SIZE 1024

// Number of root process.
#define NUMBER_ROOT_PROCESS 0

//Parse the command line arguments and fill the reference parameters.
typedef int (__cdecl *DLLParseArguments)(
    int,                                    //Count of command line tokens.
    char**,                                 //Command line tokens.
    char**,                                 //Name of input text file.
	char**,									//Name of profile text file.
    char** );                               //Name of result file.

// Write the rules of command line structure.
typedef void (__cdecl *DLLUsage)(void);

// Start the time count.
typedef void (__cdecl *DLLStart)(void);

// Stop the time count.
typedef void (__cdecl *DLLStop)(double*);

//Structure for vertices
typedef std::set<unsigned int> SetOfVertex;

//Structure for neighbors of vertices
typedef std::map<unsigned int, SetOfVertex *> Neighborhood;

//fix: Adding control tag to indicate completion
#define TAG_SEND_COMPLETE 0x0ffffff0

// Solve the Unstructured Grid problem with MPI parallelization.
class Solver
{
public:
	Solver();                                           //Constructor
    ~Solver();                                          //Destructor

    void solve(); 

    int commSize;                                       // Rank of the process.
    int commRank;                                       // Count of processes.

    bool isRootThread;                                  // Index of root process, by consideration, equal to 0.

    unsigned int numVertex;                             //Power of graph
    unsigned int numTriangles;                          //Number of triangles in grid

    double epsilon;                                     //Epsilon

    double *value;                                      //Values of verteces
    double *resultValue;                                //Reference to result array

    unsigned int *numNeighbors;                         //Number of neighbors
    unsigned int **neighborhood;                        //Array for neighbors
    unsigned int **triangles;                           //Verteces of triangles

    std::map<unsigned int, double> *localNumValue;      //map numbers - value
    std::map<unsigned int, double> *localNumValueTemp;  //temp map numbers - value
    Neighborhood *localNeighborhood;                    //map numbers - neighbors[]
    std::map<unsigned int, double> *shadowNumValue;     //map shadowNum - value
    std::map<unsigned int, unsigned int> *shadowNumProc;//map shadowNum - proc    
	
private:

};

// Settings taken from command line and input file.
class Settings
{
public:
	Settings();             //Constructor
    ~Settings();            //Destructor

    void finish(Solver *ugsolver);
    void start();
    int init(int argc, char** argv, Solver *ugsolver);
	
private:

    // Input & output files.
    char* inputFile;
    char* resultFile;
	char* profileFile;

    // Parse input file into solver's structures.
    int parseConfigFile(Solver* ugsolver); 
    
    // Write settings.
    void writeSettings(Solver *ugsolver);
};